package com.example.teacherservice.service;

import com.example.teacherservice.dto.StudentBasicDTO;
import com.example.teacherservice.dto.StudentDTO;
import com.example.teacherservice.dto.StudentDetailDTO;
import com.example.teacherservice.entity.*;
import com.example.teacherservice.entity.Class;
import com.example.teacherservice.repository.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.Hibernate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional
public class ClassService {
    private final TeaClassRepository teaClassRepository;
    private final ClassRepository classRepository;
    private final CouClassRepository couClassRepository;
    private final StudentRepository studentRepository;
    private final TeacherRepository teacherRepository;

    public List<TeaClass> findClaByTea(Long teaId) {
        try {
            return teaClassRepository.findByTeaId(teaId);
        } catch (Exception e) {
            log.error("根据教师ID查找班级失败", e);
            throw new RuntimeException("根据教师ID查找班级失败: " + e.getMessage());
        }
    }

    public Page<TeaClass> findByTeacher(int page, int limit, String name, Long teaId) {
        try {
            PageRequest pageRequest = PageRequest.of(page - 1, limit);
            if (name != null && !name.trim().isEmpty()) {
                return teaClassRepository.findByTeaIdAndClassNameContaining(teaId, name, pageRequest);
            }
            return teaClassRepository.findByTeaId(teaId, pageRequest);
        } catch (Exception e) {
            log.error("根据教师分页查找班级失败", e);
            throw new RuntimeException("根据教师分页查找班级失败: " + e.getMessage());
        }
    }

    public List<Class> findAllClasses() {
        try {
            return classRepository.findAll();
        } catch (Exception e) {
            log.error("获取所有班级失败", e);
            throw new RuntimeException("获取所有班级失败: " + e.getMessage());
        }
    }

    public Page<Class> findAllClasses(int page, int limit) {
        try {
            return classRepository.findAll(PageRequest.of(page - 1, limit));
        } catch (Exception e) {
            log.error("分页获取班级失败", e);
            throw new RuntimeException("分页获取班级失败: " + e.getMessage());
        }
    }

    public Class getClassById(Long id) {
        try {
            return classRepository.findActiveById(id)
                    .orElseThrow(() -> new RuntimeException("班级不存在或已被删除"));
        } catch (Exception e) {
            log.error("获取班级详情失败", e);
            throw new RuntimeException("获取班级详情失败: " + e.getMessage());
        }
    }

    public Class updateClass(Long id, Class classUpdate) {
        try {
            Class existingClass = getClassById(id);
            if (classUpdate.getClassName() != null) {
                existingClass.setClassName(classUpdate.getClassName());
            }
            if (classUpdate.getClassStuNum() != null) {
                existingClass.setClassStuNum(classUpdate.getClassStuNum());
            }
            return classRepository.save(existingClass);
        } catch (Exception e) {
            log.error("更新班级失败", e);
            throw new RuntimeException("更新班级失败: " + e.getMessage());
        }
    }

    public void deleteClass(Long id) {
        try {
            classRepository.softDeleteById(id);
        } catch (Exception e) {
            log.error("删除班级失败", e);
            throw new RuntimeException("删除班级失败: " + e.getMessage());
        }
    }

    public TeaClass saveClass(TeaClass teaClass) {
        try {
            return teaClassRepository.save(teaClass);
        } catch (Exception e) {
            log.error("保存班级失败", e);
            throw new RuntimeException("保存班级失败: " + e.getMessage());
        }
    }

    public void deleteClass(Long teaId, Long classId) {
        try {
            teaClassRepository.deleteByTeaIdAndClassId(teaId, classId);
        } catch (Exception e) {
            log.error("删除班级关联失败", e);
            throw new RuntimeException("删除班级关联失败: " + e.getMessage());
        }
    }

    public List<Class> batchCreateClasses(List<Class> classes) {
        try {
            return classes.stream()
                    .map(this::createClass)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("批量创建班级失败", e);
            throw new RuntimeException("批量创建班级失败: " + e.getMessage());
        }
    }

    private Class createClass(Class clazz) {
        if (classRepository.existsByClassName(clazz.getClassName())) {
            throw new RuntimeException("班级名称已存在");
        }
        return classRepository.save(clazz);
    }

    // ClassService.java

    // 通过中间表获取班级学生基本信息
    public List<Student> getStudentsByClassIdThroughStuClass(Long classId) {
        try {
            return classRepository.findStudentsByClassIdThroughStuClass(classId);
        } catch (Exception e) {
            log.error("通过中间表获取班级学生失败", e);
            throw new RuntimeException("通过中间表获取班级学生失败: " + e.getMessage());
        }
    }

    @Transactional(readOnly = true) // 添加readOnly优化
    public List<StudentDTO> getStudentsWithClassByClassId(Long classId) {
        try {
            // 在事务内完成所有数据获取和转换
            List<Student> students = classRepository.findStudentsWithClassByClassId(classId);

            return students.stream()
                    .map(student -> {
                        StudentDTO dto = new StudentDTO();
                        dto.setId(student.getId());
                        dto.setStuName(student.getStuName());
                        dto.setStuStudyTime(student.getStuStudyTime());
                        dto.setStuScore(student.getStuScore());

                        // 如果需要班级信息
                        if(student.getClassInfo() != null) {
                            dto.setClassName(student.getClassInfo().getClassName());
                        }

                        return dto;
                    })
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取班级学生及班级信息失败", e);
            throw new RuntimeException("获取班级学生及班级信息失败: " + e.getMessage());
        }
    }


    @Transactional(readOnly = true)
    public List<StudentBasicDTO> getBasicStudentsByClassId(Long classId) {
        // 直接返回DTO，避免实体序列化
        return classRepository.findBasicStudentsByClassId(classId);
    }

    // 通过中间表获取班级学生详细信息
    public List<StudentDetailDTO> getStudentsWithDetailsByClassIdThroughStuClass(Long classId) {
        try {
            List<Student> students = classRepository.findStudentsWithDetailsByClassIdThroughStuClass(classId);
            return students.stream()
                    .map(StudentDetailDTO::new)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("通过中间表获取班级学生详情失败", e);
            throw new RuntimeException("通过中间表获取班级学生详情失败: " + e.getMessage());
        }
    }

    // 通过课程ID获取学生
    public List<Student> getStudentsByCourseId(Long courseId) {
        try {
            return classRepository.findStudentsByCourseId(courseId);
        } catch (Exception e) {
            log.error("通过课程ID获取学生失败", e);
            throw new RuntimeException("通过课程ID获取学生失败: " + e.getMessage());
        }
    }

    // 通过课程ID获取学生详细信息
    public List<StudentDetailDTO> getStudentsWithDetailsByCourseId(Long courseId) {
        try {
            List<Student> students = classRepository.findStudentsWithDetailsByCourseId(courseId);
            return students.stream()
                    .map(StudentDetailDTO::new)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("通过课程ID获取学生详情失败", e);
            throw new RuntimeException("通过课程ID获取学生详情失败: " + e.getMessage());
        }
    }

    public List<Teacher> getClassTeachers(Long classId) {
        try {
            return classRepository.findTeachersByClassId(classId);
        } catch (Exception e) {
            log.error("获取班级教师失败", e);
            throw new RuntimeException("获取班级教师失败: " + e.getMessage());
        }
    }

    public List<CouClass> getClassCouClasses(Long classId) {
        try {
            List<CouClass> couClasses = classRepository.findCouClassesByClassId(classId);
            // 确保关联被初始化
            couClasses.forEach(cc -> {
                if (cc.getCourse() != null) {
                    Hibernate.initialize(cc.getCourse());
                }
                if (cc.getClassInfo() != null) {
                    Hibernate.initialize(cc.getClassInfo());
                }
            });
            return couClasses;
        } catch (Exception e) {
            log.error("获取班级课程关联失败", e);
            throw new RuntimeException("获取班级课程关联失败: " + e.getMessage());
        }
    }

    public ResponseEntity<Map<String, Object>> getClassFullDetail(Long id) {
        try {
            Class cls = getClassById(id);
            Hibernate.initialize(cls.getStudents());
            Hibernate.initialize(cls.getTeachers());
            Hibernate.initialize(cls.getCouClasses());

            // 初始化学生关联的用户数据
            cls.getStudents().forEach(student -> {
                if (student.getUser() != null) {
                    Hibernate.initialize(student.getUser());
                }
            });

            // 初始化课程数据
            cls.getCouClasses().forEach(couClass -> {
                if (couClass.getCourse() != null) {
                    Hibernate.initialize(couClass.getCourse());
                }
            });

            Map<String, Object> response = new HashMap<>();
            response.put("classInfo", cls);
            response.put("students", cls.getStudents());
            response.put("teachers", cls.getTeachers());
            response.put("couClasses", cls.getCouClasses()); // 返回完整的CouClass列表

            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("获取班级完整详情失败", e);
            throw new RuntimeException("获取班级完整详情失败: " + e.getMessage());
        }
    }
}